﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Tyche.DAO.Mapper
{
    public abstract class TycheSQLCompiler
    {
        /// <summary>
        /// SQL
        /// </summary>
        private static Dictionary<string, string> resources;

        /// <summary>
        /// 格式化后的SQL
        /// </summary>
        private static ConcurrentDictionary<string, string> formatedResources;

        /// <summary>
        /// 构造函数
        /// </summary>
        static TycheSQLCompiler()
        {
            resources = new Dictionary<string, string>();
            formatedResources = new ConcurrentDictionary<string, string>();
        }

        /// <summary>
        /// 编译SQL
        /// </summary>
        /// <param name="key"></param>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public static string Compile(string key, object parameter = null)
        {
            var formatedKey = GetItemFormatedKey(key, parameter);

            if (formatedResources.ContainsKey(formatedKey))
            {
                return formatedResources[formatedKey];
            }

            try
            {
                if (!resources.ContainsKey(key))
                {
                    throw new Exception(string.Format("无法找到key为{0}的sql", key));
                }

                var element = XElement.Parse(resources[key], LoadOptions.None);

                CompileIF(element, parameter);

                formatedResources.TryAdd(formatedKey, element.Value);

                return element.Value;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 编译if标签
        /// </summary>
        /// <param name="element"></param>
        /// <param name="parameter"></param>
        private static void CompileIF(XElement element, object parameter = null)
        {
            var elements = element.Elements("if");

            if (!elements.Any())
            {
                return;
            }

            // 如果参数为空则清除所有if标签
            if (parameter == null)
            {
                elements.Remove();
                return;
            }

            var properties = parameter.GetType().GetProperties().Where(x => x.GetValue(parameter) != null);

            // 如果全部属性都为null则清除所有if标签
            if (!properties.Any())
            {
                elements.Remove();
                return;
            }

            foreach (var item in elements)
            {
                if (!properties.Any(x => x.Name == item.Attribute("key").Value))
                {
                    item.Value = string.Empty;
                    continue;
                }

                item.Value = TryGetAttributeValue(item, "left") + item.Value + TryGetAttributeValue(item, "right");
            }
        }

        /// <summary>
        /// 根据key和parameter获取格式化后Key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="parameter"></param>
        /// <returns></returns>
        private static string GetItemFormatedKey(string key, object parameter = null)
        {
            if (parameter == null)
            {
                return key;
            }

            var parameterNames = parameter
                .GetType()
                .GetProperties()
                .Where(x => x.GetValue(parameter) != null)
                .Select(x => x.Name);

            if (!parameterNames.Any())
            {
                return key;
            }
            else
            {
                return key + "_" + string.Join("_", parameterNames);
            }
        }

        /// <summary>
        /// 尝试获取xml属性值
        /// 当没有属性时返回空字符串
        /// </summary>
        /// <param name="element"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        private static string TryGetAttributeValue(XElement element, string name)
        {
            return element.Attributes().Where(x => x.Name == name).Select(x => x.Value).FirstOrDefault() ?? string.Empty;
        }

        /// <summary>
        /// 注册资源
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        public static void RegisterResource(string key, string content)
        {
            resources.Add(key, content);
        }
    }
}
